home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / HIERSV.PAK / SVRVIEW.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  29KB  |  1,130 lines

  1. // svrview.cpp : implementation of the CServerView class
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1995 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13.  
  14.  
  15. #include "stdafx.h"
  16. #include "afxdlgs.h"        // for FileOpen
  17. #include "hiersvr.h"
  18.  
  19. #include "svrdoc.h"
  20. #include "svrview.h"
  21. #include "svritem.h"
  22. #include "zoomdlg.h"
  23.  
  24. #ifdef _DEBUG
  25. #undef THIS_FILE
  26. static char BASED_CODE THIS_FILE[] = __FILE__;
  27. #endif
  28.  
  29. CServerNode* NEAR CServerView::m_pDragNode = NULL;
  30.  
  31. static int ReadString(CArchive& ar, char* pString, int nMaxLen);
  32. static BOOL FindItemRect(CDC* pDC, CServerNode* pItemFind, LPRECT lpRect,
  33.     CPoint& ptStart, CServerNode* pRoot);
  34. static CServerNode* HitDetect(CDC* pDC, CPoint point,
  35.     CPoint& ptStart, CServerNode* pRoot);
  36.  
  37. /////////////////////////////////////////////////////////////////////////////
  38. // support for zooming
  39.  
  40. static int NEAR rgiZoomFactor[] =
  41. {
  42.     25, 50, 75, 100, 125, 150, 175, 200, 250, 300
  43. };
  44.  
  45. /////////////////////////////////////////////////////////////////////////////
  46. // CServerView
  47.  
  48. IMPLEMENT_DYNCREATE(CServerView, CScrollView)
  49.  
  50. BEGIN_MESSAGE_MAP(CServerView, CScrollView)
  51.     //{{AFX_MSG_MAP(CServerView)
  52.     ON_COMMAND(ID_CHANGE_NAME, OnChangeName)
  53.     ON_COMMAND(ID_ADD_NODE, OnAddNode)
  54.     ON_UPDATE_COMMAND_UI(ID_CHANGE_NAME, OnUpdateHasSel)
  55.     ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  56.     ON_WM_LBUTTONDOWN()
  57.     ON_WM_RBUTTONDOWN()
  58.     ON_COMMAND(ID_IMPORT_TEXT, OnImportText)
  59.     ON_COMMAND(ID_VIEW_ZOOMCUSTOM, OnViewZoomCustom)
  60.     ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  61.     ON_WM_LBUTTONDBLCLK()
  62.     ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  63.     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
  64.     ON_WM_CREATE()
  65.     ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
  66.     ON_COMMAND(ID_TREE_COLLAPSEBRANCH, OnTreeCollapsebranch)
  67.     ON_COMMAND(ID_TREE_EXPANDALL, OnTreeExpandall)
  68.     ON_COMMAND(ID_TREE_EXPANDBRANCH, OnTreeExpandbranch)
  69.     ON_COMMAND(ID_TREE_EXPANDONELEVEL, OnTreeExpandonelevel)
  70.     ON_UPDATE_COMMAND_UI(ID_TREE_COLLAPSEBRANCH, OnUpdateTreeCollapsebranch)
  71.     ON_UPDATE_COMMAND_UI(ID_TREE_EXPANDONELEVEL, OnUpdateTreeExpandonelevel)
  72.     ON_UPDATE_COMMAND_UI(ID_TREE_EXPANDALL, OnUpdateTreeExpandall)
  73.     ON_UPDATE_COMMAND_UI(ID_TREE_EXPANDBRANCH, OnUpdateTreeExpandbranch)
  74.     ON_WM_KEYDOWN()
  75.     ON_UPDATE_COMMAND_UI(ID_ADD_NODE, OnUpdateHasSel)
  76.     ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateHasSel)
  77.     ON_UPDATE_COMMAND_UI(ID_IMPORT_TEXT, OnUpdateHasSel)
  78.     ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateHasSel)
  79.     ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateHasSel)
  80.     ON_WM_SIZE()
  81.     //}}AFX_MSG_MAP
  82.     ON_COMMAND_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, OnZoom)
  83.     ON_UPDATE_COMMAND_UI_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, OnUpdateZoom)
  84. END_MESSAGE_MAP()
  85.  
  86. /////////////////////////////////////////////////////////////////////////////
  87. // CServerView construction/destruction
  88.  
  89. CServerView::CServerView()
  90. {
  91.     m_pSelectedNode = NULL;
  92.     m_ptStart = CPoint(CX_MARGIN, CY_MARGIN);   // upper left position
  93.  
  94.     // initialize zoom state (100% from size cache)
  95.     m_zoomNum = CSize(100, 100);
  96.     m_zoomDenom = CSize(100, 100);
  97.     m_prevDropEffect = DROPEFFECT_NONE;
  98. }
  99.  
  100. CServerView::~CServerView()
  101. {
  102. }
  103.  
  104. /////////////////////////////////////////////////////////////////////////////
  105. // Attributes -- public
  106.  
  107. void CServerView::SetSelection(CServerNode* pNewSel, CDC* pDC)
  108. {
  109.     if (pNewSel == m_pSelectedNode)
  110.         return;     // already set
  111.     InvalidateItem(m_pSelectedNode, pDC);
  112.     m_pSelectedNode = pNewSel;
  113.     InvalidateItem(m_pSelectedNode, pDC);
  114. }
  115.  
  116. void CServerView::SetSelection(CServerNode* pNewSel)
  117. {
  118.     CServerDC dc(this);
  119.     SetSelection(pNewSel, &dc);
  120. }
  121.  
  122. /////////////////////////////////////////////////////////////////////////////
  123. // Operations -- public
  124.  
  125. void CServerView::SetScrollInfo()
  126. {
  127.     CServerNode* pRoot = GetDocument()->m_pRoot;
  128.     ASSERT(pRoot != NULL);
  129.  
  130.     //BLOCK: determine new scrolling sizes
  131.     CSize sizeLine;
  132.     CSize sizePage;
  133.     CSize sizeTotal;
  134.     {
  135.         CServerDC dc(this);
  136.  
  137.         pRoot->CalcNodeSize(&dc, sizeLine);
  138.         sizeLine.cx = sizeDefault.cx;
  139.         sizeLine.cy += CY_SEPARATOR;
  140.         sizePage.cx = sizeDefault.cx;
  141.         sizePage.cy = sizeLine.cy * 10;
  142.  
  143.         // set the scroll sizes dependent on the zoom factor
  144.         dc.LPtoDP(&sizePage);
  145.         dc.LPtoDP(&sizeLine);
  146.         sizeTotal = CalcActualViewSize(&dc);
  147.         // subtract out the right and bottom margins
  148.         // these are not interesting and this way we avoid
  149.         // some problems with nonlinear scaling of fonts
  150.         CSize sizeMargin(CX_MARGIN, CY_MARGIN);
  151.         CRect rect(CPoint(0, 0), sizeMargin);
  152.         dc.LPtoDP(rect);
  153.         sizeTotal -= rect.Size();
  154.     }
  155.  
  156.     SetScrollSizes(MM_TEXT, sizeTotal, sizePage, sizeLine);
  157. }
  158.  
  159. BOOL CServerView::SetZoomFactor(CSize zoomNum, CSize zoomDenom)
  160. {
  161.     if (zoomDenom != m_zoomDenom || zoomNum != m_zoomNum)
  162.     {
  163.         // sync to new zoom factor
  164.         m_zoomNum = zoomNum;
  165.         m_zoomDenom = zoomDenom;
  166.  
  167.         // resync to new sizes
  168.         Invalidate();
  169.         return TRUE;
  170.     }
  171.     return FALSE;
  172. }
  173.  
  174. void CServerView::UpdateServerView()
  175. {
  176.     CServerDoc* pDoc = GetDocument();
  177.     pDoc->SetModifiedFlag();
  178.     pDoc->UpdateAllItems(NULL);
  179.     pDoc->UpdateAllViews(NULL);
  180. }
  181.  
  182. CSize CServerView::CalcActualViewSize(CDC *pDC)
  183. {
  184.     return CalcActualItemSize(GetDocument()->m_pRoot, pDC);
  185. }
  186.  
  187. CSize CServerView::CalcActualItemSize(CServerNode* pItem, CDC *pDC)
  188. {
  189.     CSize sizeTotal(0, 0);
  190.     CPoint ptStart = m_ptStart;
  191.     pItem->CalcBounding(pDC, ptStart, sizeTotal);
  192.     sizeTotal.cx += CX_MARGIN;
  193.     // sizeTotal is the extent in logical coords
  194.     // convert from logical to device
  195.     CRect rc(CPoint(0,0),sizeTotal);
  196.     pDC->LPtoDP(rc);
  197.     return rc.Size();
  198. }
  199.  
  200. CSize CServerView::CalcScaledViewSize()
  201. {
  202.     return CalcScaledItemSize(GetDocument()->m_pRoot);
  203. }
  204.  
  205. CSize CServerView::CalcScaledItemSize(CServerNode* pItem)
  206. {
  207.     CServerDC dc(this);
  208.     // set extent to 100%
  209.     dc.SetViewportExt(CSize(1,1));
  210.     dc.SetWindowExt(CSize(1,1));
  211.  
  212.     CSize sizeTotal(0, 0);
  213.     CPoint ptStart = m_ptStart;
  214.     pItem->CalcBounding(&dc, ptStart, sizeTotal);
  215.     sizeTotal.cx += CX_MARGIN;
  216.     // sizeTotal is the native extent in device coords
  217.     sizeTotal.cx = MulDiv(sizeTotal.cx,m_zoomNum.cx,m_zoomDenom.cx);
  218.     sizeTotal.cy = MulDiv(sizeTotal.cy,m_zoomNum.cy,m_zoomDenom.cy);
  219.     return sizeTotal;
  220. }
  221.  
  222. BOOL CServerView::DoPasteItem(COleDataObject* pDataObject)
  223. {
  224.     ASSERT(pDataObject != NULL);
  225.     ASSERT_VALID(this);
  226.     ASSERT(m_pSelectedNode != NULL);
  227.  
  228.     BeginWaitCursor();
  229.  
  230.     TRY
  231.     {
  232.         if (pDataObject->IsDataAvailable(CServerDoc::m_cfPrivate))
  233.             DoPasteNative(pDataObject);
  234.         else if (pDataObject->IsDataAvailable(CF_TEXT))
  235.             DoPasteText(pDataObject);
  236.         else
  237.             AfxThrowNotSupportedException();
  238.     }
  239.     CATCH_ALL(e)
  240.     {
  241.         // general cleanup
  242.         TRACE0("failed to embed/link an OLE object\n");
  243.         EndWaitCursor();
  244.         return FALSE;
  245.     }
  246.     END_CATCH_ALL
  247.  
  248.     EndWaitCursor();
  249.     return TRUE;
  250. }
  251.  
  252. void CServerView::DoPasteNative(COleDataObject *pDataObject)
  253. {
  254.     ASSERT(m_pSelectedNode != NULL);
  255.     CServerNode* pItem = new CServerNode(GetDocument());
  256.     ASSERT_VALID(pItem);
  257.  
  258.     // get file refering to clipboard data
  259.     CFile *pFile = pDataObject->GetFileData(CServerDoc::m_cfPrivate);
  260.     if (pFile == NULL)
  261.     {
  262.         delete pItem;
  263.         return;
  264.     }
  265.  
  266.     // connect the file to the archive and read the contents
  267.     CArchive ar(pFile, CArchive::load);
  268.     ar.m_pDocument = GetDocument(); // for COleClientItem serialize
  269.     pItem->Serialize(ar);
  270.     ar.Close();
  271.     delete pFile;
  272.  
  273.     // add the item to selected node
  274.     m_pSelectedNode->m_listChild.AddHead(pItem);
  275.     SetSelection(pItem);
  276. }
  277.  
  278. void CServerView::DoPasteText(COleDataObject *pDataObject)
  279. {
  280.     ASSERT(m_pSelectedNode != NULL);
  281.  
  282.     // get file refering to clipboard data
  283.     CFile *pFile = pDataObject->GetFileData(CF_TEXT);
  284.     if (pFile == NULL)
  285.         return;
  286.  
  287.     // connect the file to the archive and read the contents
  288.     CArchive ar(pFile, CArchive::load);
  289.     DoImportText(ar);
  290.     ar.Close();
  291.     delete pFile;
  292. }
  293.  
  294. void CServerView::DoImportText(CArchive &ar)
  295. {
  296.     // read in lines appending items from this node
  297.     char szNode[256];
  298. #ifdef _UNICODE
  299.     TCHAR szT[256];
  300. #endif
  301.     int nCurLevel = 0;
  302.     CServerNode* parents[MAX_LEVEL];
  303.     parents[0] = m_pSelectedNode;   // must have a parent at the current level
  304.     CServerNode* pNewSel = NULL;
  305.  
  306.     while (ReadString(ar, szNode, sizeof(szNode)) != NULL)
  307.     {
  308.         int cch = strlen(szNode);
  309.         if (cch == 0)
  310.             continue;
  311.         if (szNode[cch-1] != '\n')
  312.         {
  313.             AfxMessageBox(
  314.                 _T("Text file contains too long a line - aborting read\n"));
  315.             break;      // leaves items loaded so far
  316.         }
  317.         szNode[cch-1] = '\0';
  318.         // check the indentation level
  319.         char* pch = szNode;
  320.         while (*pch == '\t')
  321.             pch++;
  322.         int nLevel = (pch - szNode)+1;
  323.         ASSERT(nLevel >= 1);        // levels are 1 based, 0 is the root
  324.  
  325.         if (*pch == '\0')
  326.             continue;       // skip blank lines
  327.         if (nLevel > nCurLevel + 1 || nLevel >= MAX_LEVEL)
  328.         {
  329.             AfxMessageBox(
  330.                 _T("Text file contains too many tabs = aborting read\n"));
  331.             break;      // leaves items loaded so far
  332.         }
  333.  
  334. #ifdef _UNICODE
  335.         _mbstowcsz(szT, pch, sizeof(szT)/sizeof(szT[0]));
  336.         parents[nLevel] = parents[nLevel-1]->CreateChildNode(szT);
  337. #else
  338.         parents[nLevel] = parents[nLevel-1]->CreateChildNode(pch);
  339. #endif
  340.         nCurLevel = nLevel;
  341.         if (pNewSel == NULL)
  342.             pNewSel = parents[nLevel];
  343.     }
  344.     if (nCurLevel == 0)
  345.         return;     // nothing added
  346.  
  347.     SetSelection(pNewSel);
  348.     UpdateServerView();
  349. }
  350.  
  351. void CServerView::ScrollToItem(CServerNode *pItem, BOOL bScrollUp)
  352. {
  353.     CServerDC dc(this);
  354.  
  355.     CRect rect;
  356.     CPoint ptStart = m_ptStart;
  357.     if (FindItemRect(&dc, pItem, &rect, ptStart, GetDocument()->m_pRoot))
  358.     {
  359.         CRect rc;
  360.         dc.LPtoDP(rect);
  361.         if (GetDocument()->IsInPlaceActive())
  362.         {
  363.             CRect rcPos,rcClip;
  364.             GetDocument()->GetItemPosition(&rcPos);
  365.             GetDocument()->GetItemClipRect(&rcClip);
  366.             rc.IntersectRect(&rcPos,&rcClip);
  367.             rc.OffsetRect(-rcPos.left,-rcPos.top);
  368.             if (!rc.PtInRect(rect.TopLeft()) || !rc.PtInRect(rect.BottomRight()))
  369.             {
  370.                 CSize size(0, 0);
  371.                 // scroll inplace site
  372.                 if (bScrollUp)
  373.                     size.cy = rect.top - rc.top;
  374.                 else
  375.                     size.cy = rect.bottom + rcPos.top - rcClip.bottom;
  376.                 GetDocument()->ScrollContainerBy(size);
  377.             }
  378.         }
  379.         else
  380.         {
  381.             GetClientRect(rc);
  382.             if (!rc.PtInRect(rect.TopLeft()) || !rc.PtInRect(rect.BottomRight()))
  383.             {
  384.                 CPoint ptDevScroll = GetDeviceScrollPosition();
  385.                 if (bScrollUp)
  386.                     ScrollToPosition(CPoint(0,rect.top + ptDevScroll.y));
  387.                 else
  388.                     ScrollToPosition(
  389.                         CPoint(0,ptDevScroll.y + rect.bottom - rc.Height()));
  390.             }
  391.         }
  392.     }
  393. }
  394.  
  395. void CServerView::Locate(int nCount, BOOL bScrollUp)
  396. {
  397.     CServerNode* pRoot = GetDocument()->m_pRoot;
  398.     CServerNode* pItem = pRoot;
  399.  
  400.     if (m_pSelectedNode == NULL)
  401.         SetSelection(pRoot);
  402.  
  403.     if (nCount == 0) // goto top or bottom depending on direction
  404.     {
  405.         if (bScrollUp)
  406.             pItem = pRoot;
  407.         else
  408.         {
  409.             while (pItem->HasChildren())
  410.                 pItem = (CServerNode *)(pItem->m_listChild.GetTail());
  411.         }
  412.     }
  413.     else if (bScrollUp)
  414.     {
  415.         pItem = m_pSelectedNode;
  416.         while (nCount--)
  417.             pItem = pRoot->GetPrev(pItem);
  418.     }
  419.     else // going down
  420.     {
  421.         pItem = m_pSelectedNode;
  422.         while (nCount--)
  423.             pItem = pRoot->GetNext(pItem);
  424.     }
  425.     ScrollToItem(pItem, bScrollUp);
  426.     SetSelection(pItem);
  427.     UpdateWindow();
  428. }
  429.  
  430. void CServerView::InvalidateItem(CServerNode *pItem, CDC* pDC)
  431. {
  432.     if (pItem != NULL)
  433.     {
  434.         CRect rect;
  435.         CPoint ptStart = m_ptStart;
  436.         if (FindItemRect(pDC, pItem, &rect, ptStart, GetDocument()->m_pRoot))
  437.         {
  438.             pDC->LPtoDP(rect);
  439.             InvalidateRect(rect, FALSE);
  440.         }
  441.     }
  442. }
  443.  
  444. void CServerView::InvalidateItem(CServerNode* pItem)
  445. {
  446.     CServerDC dc(this);
  447.     InvalidateItem(pItem, &dc);
  448. }
  449.  
  450. void CServerView::ToggleSelectedItem()
  451. {
  452.     if (m_pSelectedNode != NULL && m_pSelectedNode->HasChildren())
  453.     {
  454.         if (m_pSelectedNode->m_bHideChildren)
  455.             OnTreeExpandonelevel();
  456.         else
  457.             OnTreeCollapsebranch();
  458.     }
  459. }
  460.  
  461. /////////////////////////////////////////////////////////////////////////////
  462. // Implementation
  463.  
  464. void CServerView::OnDraw(CDC* pDC)
  465. {
  466.     if (GetDocument()->DrawTree(pDC, m_ptStart, m_pSelectedNode) == -1)
  467.         TRACE0("Error: CServerDoc::DrawTree failed!!\n");
  468. }
  469.  
  470. void CServerView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
  471. {
  472.     CScrollView::OnUpdate(pSender, lHint, pHint);
  473.     CServerDoc* pDoc = GetDocument();
  474.     CServerNode* pRoot = pDoc->m_pRoot;
  475.     ASSERT(pRoot != NULL);
  476.  
  477.     if (m_pSelectedNode == NULL)
  478.         m_pSelectedNode = pRoot;
  479.  
  480.     if (pDoc->IsInPlaceActive())
  481.     {
  482.         ASSERT_VALID(pDoc->m_pRoot);
  483.         CRect rect;
  484.         pDoc->GetItemPosition(rect);
  485.  
  486.         // adjust rect for new size of view
  487.         rect.BottomRight() = rect.TopLeft() + CalcScaledViewSize();
  488.         pDoc->RequestPositionChange(rect);
  489.             // may resize the window before returning
  490.     }
  491.     SetScrollInfo();
  492. }
  493.  
  494. void CServerView::OnInitialUpdate()
  495. {
  496.     // initialize zoom state (100% from size cache)
  497.     m_zoomNum = CSize(100, 100);
  498.     m_zoomDenom = CSize(100, 100);
  499.  
  500.     // call base class last (will call OnUpdate)
  501.     CScrollView::OnInitialUpdate();
  502. }
  503.  
  504. void CServerView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  505. {
  506.     CScrollView::OnPrepareDC(pDC, pInfo);
  507.  
  508.     pDC->SetMapMode(MM_ANISOTROPIC);
  509.     pDC->SetViewportExt(m_zoomNum);
  510.     pDC->SetWindowExt(m_zoomDenom);
  511. }
  512.  
  513. void CServerView::SelectAtPoint(CPoint point, CPoint& pointHit)
  514. {
  515.     CServerDC dc(this);
  516.  
  517.     // change the selection as appropriate
  518.     pointHit = m_ptStart;
  519.     CServerNode* pSelection = HitDetect(&dc, point, pointHit,
  520.         GetDocument()->m_pRoot);
  521.  
  522.     // now set the selection to new hit-tested node
  523.     SetSelection(pSelection, &dc);
  524. }
  525.  
  526. void CServerView::DoBranch(CServerNode *pItem, BOOL bHide)
  527. {
  528.     if (pItem->HasChildren())
  529.     {
  530.         pItem->m_bHideChildren = bHide;
  531.         POSITION pos = pItem->m_listChild.GetHeadPosition();
  532.         while (pos != NULL)
  533.             DoBranch((CServerNode *)pItem->m_listChild.GetNext(pos),bHide);
  534.     }
  535. }
  536.  
  537. BOOL CServerView::OnDrop(COleDataObject* pDataObject, DROPEFFECT, CPoint)
  538. {
  539.     ASSERT_VALID(this);
  540.     OnDragLeave();
  541.     if (DoPasteItem(pDataObject))
  542.     {
  543.         UpdateServerView();
  544.         return TRUE;
  545.     }
  546.     else
  547.         return FALSE;
  548. }
  549.  
  550. DROPEFFECT CServerView::OnDragEnter(COleDataObject* pDataObject,
  551.     DWORD grfKeyState, CPoint point)
  552. {
  553.     ASSERT(m_prevDropEffect == DROPEFFECT_NONE);
  554.     return OnDragOver(pDataObject, grfKeyState, point);
  555. }
  556.  
  557. DROPEFFECT CServerView::OnDragOver(COleDataObject* pDataObject,
  558.     DWORD grfKeyState, CPoint point)
  559. {
  560.     DROPEFFECT dropEffect = DROPEFFECT_NONE;
  561.     if (pDataObject->IsDataAvailable(CServerDoc::m_cfPrivate) ||
  562.         pDataObject->IsDataAvailable(CF_TEXT))
  563.     {
  564.         CPoint pointHit;
  565.         SelectAtPoint(point, pointHit);
  566.         UpdateWindow();
  567.         if (m_pSelectedNode != NULL)
  568.         {
  569.             // don't allow a node to drop on itself
  570.             if (m_pDragNode == m_pSelectedNode)
  571.                 dropEffect = DROPEFFECT_NONE;
  572.             // if drop target is a child of drag source
  573.             // then don't drop
  574.             else if (m_pDragNode != NULL && m_pDragNode->IsChild(m_pSelectedNode))
  575.                 dropEffect = DROPEFFECT_NONE;
  576.             // check for force link
  577. #ifndef _MAC            
  578.             else if ((grfKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
  579. #else
  580.             else if ((grfKeyState & (MK_OPTION|MK_SHIFT)) == (MK_OPTION|MK_SHIFT))
  581. #endif            
  582.                 dropEffect = DROPEFFECT_COPY;
  583.             // check for force copy
  584. #ifndef _MAC            
  585.             else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
  586. #else                
  587.             else if ((grfKeyState & MK_OPTION) == MK_OPTION)
  588. #endif            
  589.                 dropEffect = DROPEFFECT_COPY;
  590.             // check for force move
  591.             else if ((grfKeyState & MK_ALT) == MK_ALT)
  592.                 dropEffect = DROPEFFECT_MOVE;
  593.             // if m_pDragNode == NULL then not dropping on self
  594.             // so make default effect be copy
  595.             // if dropping on self make default be move
  596.             else
  597.                 dropEffect = (m_pDragNode == NULL) ? DROPEFFECT_COPY :
  598.                     DROPEFFECT_MOVE;
  599.         }
  600.     }
  601.     m_prevDropEffect = dropEffect;
  602.     return dropEffect;
  603. }
  604.  
  605. void CServerView::OnDragLeave()
  606. {
  607.     m_prevDropEffect = DROPEFFECT_NONE;
  608. }
  609.  
  610. /////////////////////////////////////////////////////////////////////////////
  611. // CServerView commands
  612.  
  613. void CServerView::OnUpdateHasSel(CCmdUI* pCmdUI)
  614. {
  615.     pCmdUI->Enable(m_pSelectedNode != NULL);
  616. }
  617.  
  618. void CServerView::OnChangeName()
  619. {
  620.     if (m_pSelectedNode != NULL && m_pSelectedNode->PromptChangeNode())
  621.     {
  622.         GetDocument()->SetModifiedFlag();
  623.         GetDocument()->UpdateAllItems(NULL);
  624.         GetDocument()->UpdateAllViews(NULL);
  625.     }
  626. }
  627.  
  628. void CServerView::OnAddNode()
  629. {
  630.     if (m_pSelectedNode == NULL)
  631.         AfxThrowNotSupportedException();
  632.     CServerNode* pNew;
  633.     if ((pNew = m_pSelectedNode->PromptNewChildNode()) == NULL)
  634.         return;
  635.  
  636.     SetSelection(pNew);
  637.     UpdateServerView();
  638. }
  639.  
  640. void CServerView::OnEditCopy()
  641. {
  642.     ASSERT_VALID(this);
  643.     if (m_pSelectedNode == NULL)
  644.         return;
  645.  
  646.     // get a server item suitable to generate the clipboard data
  647.     CServerItem* pItem = m_pSelectedNode->m_pServerItem;
  648.     if (pItem == NULL)
  649.         pItem = new CServerItem(GetDocument(), m_pSelectedNode);
  650.     ASSERT_VALID(pItem);
  651.  
  652.     pItem->CopyToClipboard(TRUE);
  653. }
  654.  
  655. void CServerView::OnLButtonDown(UINT, CPoint point)
  656. {
  657.     // m_pDragNode != NULL only when drag in progress
  658.     ASSERT(m_pDragNode == NULL);
  659.     CPoint pointHit;
  660.     SelectAtPoint(point, pointHit);
  661.     UpdateWindow();
  662.  
  663.     // maybe start drag drop operation on selection
  664.     if (m_pSelectedNode != NULL)
  665.     {
  666.         // record current selection because a drop back in same view
  667.         // will change the current selection
  668.         m_pDragNode = m_pSelectedNode;
  669.  
  670.         // determine rectangle of object we'll be dragging
  671.         CServerDC dc(this);
  672.         CSize size = CalcActualItemSize(m_pSelectedNode, &dc);
  673.         CRect rect(pointHit, size);
  674.  
  675.         // get a server item suitable to generate the clipboard data
  676.         CServerItem* pItem = m_pSelectedNode->m_pServerItem;
  677.         if (pItem == NULL)
  678.             pItem = new CServerItem(GetDocument(), m_pSelectedNode);
  679.         ASSERT_VALID(pItem);
  680.  
  681.         // rect must be in screen co-ordinates
  682.         dc.LPtoDP(&rect);
  683.         CPoint ptOffset = point - rect.TopLeft();
  684.         ClientToScreen(&rect);
  685.  
  686.         // drag the object
  687.         if (pItem->DoDragDrop(rect, ptOffset, TRUE,
  688.             DROPEFFECT_COPY | DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
  689.         {
  690.             // the object was moved, need to delete/move depending on dest
  691.             CServerDoc* pDoc = GetDocument();
  692.             if (m_pSelectedNode == m_pDragNode)
  693.                 SetSelection(pDoc->m_pRoot->GetPrev(m_pSelectedNode));
  694.             if (m_pDragNode == pDoc->m_pRoot)
  695.                 pDoc->m_pRoot->InitRootNode();
  696.             else
  697.                 pDoc->m_pRoot->FindAndDelete(m_pDragNode);
  698.  
  699.             // if drop was not back in same view clear selected node
  700.             UpdateServerView();
  701.         }
  702.         m_pDragNode = NULL;
  703.     }
  704. }
  705.  
  706. void CServerView::OnRButtonDown(UINT /*nFlags*/, CPoint point)
  707. {
  708.     // make sure window is active
  709.     GetParentFrame()->ActivateFrame();
  710.  
  711.     CPoint pointHit;
  712.     SelectAtPoint(point, pointHit); // select node first
  713.     UpdateWindow();
  714.  
  715.     int iSub;
  716.     if (m_pSelectedNode == NULL ||
  717.       (iSub = m_pSelectedNode->GetPopupMenuIndex()) == -1)
  718.        return;  // nothing if no selection or no popup
  719.  
  720.     CMenu popups;
  721.     if (!popups.LoadMenu(IDR_POPUPS))
  722.         AfxThrowResourceException();
  723.     CMenu* pMenu = popups.GetSubMenu(iSub);
  724.     ASSERT(pMenu != NULL);
  725.  
  726.     ClientToScreen(&point);
  727.     pMenu->TrackPopupMenu(TPM_CENTERALIGN | TPM_RIGHTBUTTON,
  728.         point.x, point.y, AfxGetMainWnd());
  729. }
  730.  
  731. void CServerView::OnImportText()
  732. {
  733.     if (m_pSelectedNode == NULL)
  734.         AfxThrowNotSupportedException();
  735.  
  736.     CFileDialog dlg(TRUE, _T("txt"), NULL,
  737.         OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
  738. #ifdef _MAC
  739.         _T("Text Files|TEXT|All Files|****||"));
  740. #else
  741.         _T("Text Files (*.txt)|*.txt|All Files (*.*)|*.*||"));
  742. #endif
  743.     if (dlg.DoModal() != IDOK)
  744.         return;                 // stay with old data file
  745.  
  746.     CFile file;
  747.     if (!file.Open(dlg.GetPathName(), CFile::modeRead))
  748.     {
  749.         AfxMessageBox(_T("Failed to open text file"));
  750.         return;
  751.     }
  752.  
  753.     CArchive ar(&file,CArchive::load);
  754.     DoImportText(ar);
  755.     ar.Close();
  756.     file.Close();
  757. }
  758.  
  759. static int ReadString(CArchive& ar, char* pString, int nMaxLen)
  760. {
  761.     int nCount = 0;
  762.     char ch;
  763.     pString[nCount] = (char)0;
  764.     TRY
  765.     {
  766.         do
  767.         {
  768.             ar >> (BYTE&)ch;
  769.  
  770.             // watch out for ^Z (EOF under DOS)
  771.             if (ch == 0x1A)
  772.                 break;
  773.  
  774.             // combine "\r\n" pair into single "\n"
  775.             if (ch == '\n' && nCount != 0 && pString[nCount-1] == '\r')
  776.                 nCount--;
  777.  
  778.             pString[nCount++] = ch;
  779.  
  780.         } while (nCount < nMaxLen-1 && ch != '\n');
  781.     }
  782.     END_TRY
  783.  
  784. #ifdef _OLD
  785.     // insert newline if missing
  786.     if (nCount != 0 && pString[nCount-1] != '\n' && nCount < nMaxLen-1)
  787.         pString[nCount++] = '\n';
  788.     pString[nCount] = (char)0;
  789. #else
  790.     // insert newline if missing
  791.     if (nCount != 0 && pString[nCount-1] != '\n' && nCount < nMaxLen-1)
  792.     {
  793.         if (pString[nCount-1] == '\0')
  794.             pString[nCount-1] = '\n';
  795.         else
  796.             pString[nCount++] = '\n';
  797.     }
  798.     pString[nCount] = (char)0;
  799. #endif
  800.     return nCount;
  801. }
  802.  
  803. /////////////////////////////////////////////////////////////////////////////
  804. // Zooming user interface
  805.  
  806. void CServerView::OnZoom(UINT nID)
  807. {
  808.     ASSERT(nID >= ID_VIEW_ZOOM25 && nID <= ID_VIEW_ZOOM300);
  809.  
  810.     CSize zoomDenom;
  811.     CSize zoomNum;
  812.  
  813.     // all of our zoom factors use denominator of 100
  814.     zoomDenom.cx = 100;
  815.     zoomDenom.cy = 100;
  816.  
  817.     // get zoom factor numerator and set it
  818.     ASSERT(nID-ID_VIEW_ZOOM25 < sizeof(rgiZoomFactor)/sizeof(rgiZoomFactor[0]));
  819.     int iZoomFactor = rgiZoomFactor[nID-ID_VIEW_ZOOM25];
  820.     zoomNum.cx = iZoomFactor;
  821.     zoomNum.cy = iZoomFactor;
  822.  
  823.     // change the zoom factor to new zoom factor
  824.     SetZoomFactor(zoomNum, zoomDenom);
  825.     SetScrollInfo();
  826. }
  827.  
  828. void CServerView::OnUpdateZoom(CCmdUI* pCmdUI)
  829. {
  830.     UINT nID = pCmdUI->m_nID;
  831.  
  832.     if (m_zoomDenom.cx == 100 && m_zoomDenom.cy == 100 &&
  833.         nID != ID_VIEW_ZOOMCUSTOM)
  834.     {
  835.         ASSERT(nID-ID_VIEW_ZOOM25 <
  836.             sizeof(rgiZoomFactor)/sizeof(rgiZoomFactor[0]));
  837.         int iZoomFactor = rgiZoomFactor[nID-ID_VIEW_ZOOM25];
  838.  
  839.         if (iZoomFactor == m_zoomNum.cx && iZoomFactor == m_zoomNum.cy)
  840.         {
  841.             pCmdUI->SetCheck(TRUE);
  842.             return;
  843.         }
  844.     }
  845.  
  846.     // default to not checked
  847.     pCmdUI->SetCheck(FALSE);
  848. }
  849.  
  850. void CServerView::OnViewZoomCustom()
  851. {
  852.     // prepare dialog data
  853.     CZoomDlg dlg;
  854.     dlg.m_zoomX = m_zoomNum.cx;
  855.     dlg.m_zoomY = m_zoomNum.cy;
  856.  
  857.     // launch dialog
  858.     if (dlg.DoModal() == IDOK)
  859.     {
  860.         // set new zoom factors
  861.         CSize zoomNum(dlg.m_zoomX, dlg.m_zoomY);
  862.         SetZoomFactor(zoomNum, m_zoomDenom);
  863.         SetScrollInfo();
  864.     }
  865. }
  866.  
  867. /////////////////////////////////////////////////////////////////////////////
  868.  
  869. void CServerView::OnEditCut()
  870. {
  871.     ASSERT(m_pSelectedNode != NULL);
  872.     CServerDoc* pDoc = GetDocument();
  873.     OnEditCopy();
  874.     if (m_pSelectedNode == pDoc->m_pRoot)
  875.         pDoc->m_pRoot->InitRootNode();
  876.     else if (pDoc->m_pRoot->FindAndDelete(m_pSelectedNode))
  877.         m_pSelectedNode = NULL;
  878.     UpdateServerView();
  879. }
  880.  
  881. void CServerView::OnLButtonDblClk(UINT /*nFlags*/, CPoint point)
  882. {
  883.     CPoint pointHit;
  884.     SelectAtPoint(point, pointHit);
  885.     ToggleSelectedItem();
  886. }
  887.  
  888. void CServerView::OnEditPaste()
  889. {
  890.     COleDataObject clipboardData;
  891.     clipboardData.AttachClipboard();
  892.     DoPasteItem(&clipboardData);
  893.     UpdateServerView();
  894. }
  895.  
  896. void CServerView::OnUpdateEditPaste(CCmdUI* pCmdUI)
  897. {
  898.     // determine if private or standard OLE formats are on the clipboard
  899.     COleDataObject dataObj;
  900.     BOOL bEnable = m_pSelectedNode != NULL &&
  901.         dataObj.AttachClipboard() &&
  902.         (dataObj.IsDataAvailable(CServerDoc::m_cfPrivate) ||
  903.          dataObj.IsDataAvailable(CF_TEXT));
  904.     // enable command based on availability
  905.     pCmdUI->Enable(bEnable);
  906. }
  907.  
  908. int CServerView::OnCreate(LPCREATESTRUCT lpCreateStruct)
  909. {
  910.     if (CScrollView::OnCreate(lpCreateStruct) == -1)
  911.         return -1;
  912.  
  913.     // register drop target
  914.     m_dropTarget.Register(this);
  915.  
  916.     // setup scroll state so it is possible to calculate the extent
  917.     SetScrollSizes(MM_TEXT, CSize(0, 0));
  918.  
  919.     return 0;
  920. }
  921.  
  922. void CServerView::OnEditClear()
  923. {
  924.     CServerNode* pRoot = GetDocument()->m_pRoot;
  925.     if (m_pSelectedNode == NULL)
  926.         return;
  927.     if (m_pSelectedNode == pRoot)
  928.         pRoot->InitRootNode();
  929.     else
  930.     {
  931.         CServerNode *pItem = pRoot->GetPrev(m_pSelectedNode);
  932.         if (pRoot->FindAndDelete(m_pSelectedNode))
  933.             m_pSelectedNode = pRoot->GetNext(pItem);
  934.     }
  935.     UpdateServerView();
  936. }
  937.  
  938. void CServerView::OnTreeCollapsebranch()
  939. {
  940.     DoBranch(m_pSelectedNode,TRUE);
  941.     UpdateServerView();
  942. }
  943.  
  944. void CServerView::OnTreeExpandall()
  945. {
  946.     DoBranch(GetDocument()->m_pRoot,FALSE);
  947.     UpdateServerView();
  948. }
  949.  
  950. void CServerView::OnTreeExpandbranch()
  951. {
  952.     DoBranch(m_pSelectedNode,FALSE);
  953.     UpdateServerView();
  954. }
  955.  
  956. void CServerView::OnTreeExpandonelevel()
  957. {
  958.     if (m_pSelectedNode->HasChildren())
  959.     {
  960.         m_pSelectedNode->m_bHideChildren = FALSE;
  961.         UpdateServerView();
  962.     }
  963. }
  964.  
  965. void CServerView::OnUpdateTreeCollapsebranch(CCmdUI* pCmdUI)
  966. {
  967.     pCmdUI->Enable(m_pSelectedNode != NULL && m_pSelectedNode->HasChildren() &&
  968.         !m_pSelectedNode->m_bHideChildren);
  969. }
  970.  
  971. void CServerView::OnUpdateTreeExpandonelevel(CCmdUI* pCmdUI)
  972. {
  973.     pCmdUI->Enable(m_pSelectedNode != NULL && m_pSelectedNode->HasChildren() &&
  974.         m_pSelectedNode->m_bHideChildren);
  975. }
  976.  
  977. void CServerView::OnUpdateTreeExpandall(CCmdUI* pCmdUI)
  978. {
  979.     pCmdUI->Enable(GetDocument()->m_pRoot != NULL &&
  980.         GetDocument()->m_pRoot->HasChildren());
  981. }
  982.  
  983. void CServerView::OnUpdateTreeExpandbranch(CCmdUI* pCmdUI)
  984. {
  985.     pCmdUI->Enable(m_pSelectedNode != NULL && m_pSelectedNode->HasChildren());
  986. }
  987.  
  988. void CServerView::OnKeyDown(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
  989. {
  990.     switch (nChar)
  991.     {
  992.         case VK_RETURN:
  993.             ToggleSelectedItem();
  994.             break;
  995.         case VK_UP:
  996.             Locate(1, TRUE);
  997.             break;
  998.         case VK_DOWN:
  999.             Locate(1, FALSE);
  1000.             break;
  1001.         case VK_HOME:
  1002.             Locate(0, TRUE);
  1003.             break;
  1004.         case VK_END:
  1005.             Locate(0, FALSE);
  1006.             break;
  1007.         case VK_PRIOR:
  1008.             Locate(10, TRUE);
  1009.             break;
  1010.         case VK_NEXT:
  1011.             Locate(10, FALSE);
  1012.             break;
  1013.     }
  1014. }
  1015.  
  1016. void CServerView::OnSize(UINT nType, int cx, int cy)
  1017. {
  1018.     // update scroll bar size before handling the size message
  1019.     //  (this avoids multiple updates during in-place activation)
  1020.     SetScrollInfo();
  1021.  
  1022.     CScrollView::OnSize(nType, cx, cy);
  1023. }
  1024.  
  1025. /////////////////////////////////////////////////////////////////////////////
  1026. // CServerDC class -- helper for setting up and cleaning up DC
  1027.  
  1028. CServerDC::CServerDC(CServerView *pView) : CClientDC(pView)
  1029. {
  1030.     pView->OnPrepareDC(this);
  1031.     pOldFont = pView->GetDocument()->SelectDocFont(this, font);
  1032. }
  1033.  
  1034. CServerDC::~CServerDC()
  1035. {
  1036.     if (pOldFont != NULL)
  1037.         SelectObject(pOldFont);
  1038. }
  1039.  
  1040. /////////////////////////////////////////////////////////////////////////////
  1041. // non-member static functions
  1042.  
  1043. // calculate the bounding rect for a given item in the context of this view
  1044. static BOOL FindItemRect(CDC* pDC, CServerNode* pItemFind, LPRECT lpRect,
  1045.     CPoint& ptStart, CServerNode* pRoot)
  1046. {
  1047.     ASSERT(pItemFind != NULL);
  1048.     ASSERT(lpRect != NULL);
  1049.     ASSERT(pRoot != NULL);
  1050.  
  1051.     CSize sizeNode;
  1052.     pRoot->CalcNodeSize(pDC, sizeNode);
  1053.     if (pItemFind == pRoot)
  1054.     {
  1055.         // item rect does not include separator
  1056.         lpRect->right = (lpRect->left = ptStart.x) + sizeNode.cx;
  1057.         lpRect->bottom = (lpRect->top = ptStart.y) + sizeNode.cy;
  1058.         return TRUE;
  1059.     }
  1060.  
  1061.     CPoint pt(CX_INDENT, CY_SEPARATOR);
  1062.     ptStart.x += CX_INDENT; // not essential for calculation
  1063.     ptStart.y += sizeNode.cy + CY_SEPARATOR;
  1064.  
  1065.     // check the kids
  1066.     if (!pRoot->m_bHideChildren)
  1067.     {
  1068.         POSITION pos = pRoot->m_listChild.GetHeadPosition();
  1069.         while (pos != NULL)
  1070.         {
  1071.             CServerNode* pChild = (CServerNode*) (pRoot->m_listChild.GetNext(pos));
  1072.             if (FindItemRect(pDC, pItemFind, lpRect, ptStart, pChild))
  1073.                 return TRUE;    // found
  1074.         }
  1075.     }
  1076.     ptStart.x -= CX_INDENT;
  1077.     return FALSE;
  1078. }
  1079.  
  1080. // calculate the bounding rect for a given item in the context of this view
  1081. static CServerNode* HitDetect(CDC* pDC, CPoint point,
  1082.     CPoint& ptStart, CServerNode* pRoot)
  1083. {
  1084.     ASSERT(pRoot != NULL);
  1085.  
  1086.     CSize sizeNode;
  1087.     pRoot->CalcNodeSize(pDC, sizeNode);
  1088.     CRect rect(ptStart, sizeNode);
  1089.     pDC->LPtoDP(rect);
  1090.     if (rect.PtInRect(point))
  1091.         return pRoot;
  1092.  
  1093.     ptStart.x += CX_INDENT;
  1094.     ptStart.y += sizeNode.cy + CY_SEPARATOR;
  1095.     CPoint pt = ptStart;
  1096.     pDC->LPtoDP(&pt);
  1097.     if (pt.y >= point.y)
  1098.         return FALSE;       // no point in looking any lower
  1099.  
  1100.     // check the kids
  1101.     if (!pRoot->m_bHideChildren)
  1102.     {
  1103.         POSITION pos = pRoot->m_listChild.GetHeadPosition();
  1104.         while (pos != NULL)
  1105.         {
  1106.             CServerNode* pChild = (CServerNode*) (pRoot->m_listChild.GetNext(pos));
  1107.             CServerNode* pItem = HitDetect(pDC, point, ptStart, pChild);
  1108.             if (pItem != NULL)
  1109.                 return pItem;   // found
  1110.         }
  1111.     }
  1112.     ptStart.x -= CX_INDENT;
  1113.     return NULL;
  1114. }
  1115.  
  1116. /////////////////////////////////////////////////////////////////////////////
  1117. // CServerView diagnostics
  1118.  
  1119. #ifdef _DEBUG
  1120. void CServerView::AssertValid() const
  1121. {
  1122.     CScrollView::AssertValid();
  1123. }
  1124.  
  1125. void CServerView::Dump(CDumpContext& dc) const
  1126. {
  1127.     CScrollView::Dump(dc);
  1128. }
  1129. #endif //_DEBUG
  1130.